// file:include/os/memspace.h
// autor:jiangxinpeng
// time:2021.3.4
// copyright:(C) by jiangxinpeng,All right are reserved.

#ifndef OS_MEMSPACE_H
#define OS_MEMSPACE_H

#include <lib/type.h>
#include <lib/list.h>
#include <os/vmm.h>
#include <arch/pymem.h>

#define MEM_SPACE_HEAP_SIZE_MAX 512 * MB

// mem space map flags
#define MEM_SPACE_MAP_FIXED 0x01 // fixed area
#define MEM_SPACE_MAP_STACK 0x02 // stack area
#define MEM_SPACE_MAP_HEAP 0x04  // head  area
#define MEM_SPACE_MAP_SHARE 0x08 // share area
#define MEM_SPACE_MAP_REMAP 0x10 // remap area

#define MEM_SPACE_STACK_SIZE_DEFAULT (6 * PAGE_SIZE)

#define MEM_SPACE_MAP_BASE_START (USER_SPACE_START_ADDR + 0x60000000)
#define MEM_SPACE_MAP_SIZE (64 * MB)
#define MEM_SPACE_MAP_BASE_END (MEM_SPACE_MAP_BASE_START + MEM_SPACE_MAP_SIZE)

typedef struct
{
    uint64_t start;   // space start addr
    uint64_t end;     // space end addr
    uint64_t protect; // space protect
    uint64_t flags;   // space map flags
    vmm_t *vmm;       // vmm point
    list_t list;      // space list
} mem_space_t;

typedef struct
{
    void *addr;
    size_t len;
    int prot;
    int flags;
    int fd;
    offset_t off;
} mmap_args_t;

#define MemSpaceAlloc() KMemAlloc(sizeof(mem_space_t))
#define MemSpaceFree KMemFree

void MemSpaceInsert(vmm_t *vmm, mem_space_t *space);
uint64_t MemSpaceGetUnMap(vmm_t *vmm, uint32_t len);
mem_space_t *MemSpaceFind(vmm_t *vmm, uint64_t addr);
void *MemSpaceMap(vmm_t *vmm, uint64_t addr, uint64_t pyaddr, uint64_t len, uint64_t protect, uint64_t flags);
int MemSpaceUnmap(vmm_t *vmm, uint64_t addr, uint64_t len);
mem_space_t *MemSpaceFindPre(vmm_t *vmm, uint64_t addr);
void *MemSpaceMapViraddr(vmm_t *vmm, uint32_t addr, uint32_t vaddr, uint32_t len, uint32_t prot, uint32_t flags);
uint32_t SysMemSpaceExpandHeap(uint32_t heap);
void MemSpaceTest();

static inline void MemSpaceRemove(vmm_t *vmm, mem_space_t *space)
{
    list_del_init(&space->list);
    MemSpaceFree(space);
}

static inline mem_space_t *MemSpaceFindIntersection(vmm_t *vmm, uint64_t start, uint64_t end)
{
    mem_space_t *space = MemSpaceFind(vmm, start);
    // first space start upper than second space end
    if (space && space->start >= end)
    {
        return space;
    }
    return NULL;
}

static inline void MemSpaceInit(mem_space_t *space, uint64_t start, uint64_t end, uint64_t flags, uint64_t protect)
{
    space->start = start;
    space->end = end;
    space->flags = flags;
    space->protect = protect;
    list_init(&space->list);
}

#endif